package com.zpengblog.top.messagecenter.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注册Websocket的服务端.
 *
 * serverEndpoint指定服务端的访问路径
 *
 * @author linzp
 * @version 1.0.0
 * CreateDate 2020/8/6 22:55
 */
@Slf4j
@Component
@ServerEndpoint("/messageCenter/{orgId}")
public class WebsocketServer {

    /**
     * 用来存储在线用户session的线程安全集合.
     */
    private static Map<String, List<Session>> connectSession = new ConcurrentHashMap<>();

    /**
     * 连接socket调用.
     *
     * @param orgId   连接的机构id，根据此参数分组
     * @param session 用户连接
     */
    @OnOpen
    public void connect(Session session, @PathParam("orgId") String orgId) {
        if (StringUtils.isBlank(orgId)){
            log.error("机构信息为空，不允许连接！");
        }
        //当前在线用户为空
        if (connectSession.isEmpty()){
            List<Session> sessionList = new ArrayList<>();
            sessionList.add(session);
            connectSession.put(orgId, sessionList);
        }else {
            //已包含该机构的用户
            if (connectSession.containsKey(orgId)) {
                List<Session> sessions = connectSession.get(orgId);
                //添加当前用户到列表
                sessions.add(session);
                connectSession.put(orgId, sessions);
            }else {
                //新机构的用户
                List<Session> sessionList = new ArrayList<>();
                sessionList.add(session);
                connectSession.put(orgId, sessionList);
            }
        }
        log.info("添加用户连接成功>>>机构【{}】", orgId);
        log.info("当前所有连接信息>>>【{}】", connectSession);
    }

    /**
     * 推送消息时调用.
     */
    @OnMessage
    public void sendMessage(String msg) {
        log.info("接收到消息：【{}】", msg);
    }

    /**
     * 给指定机构推送消息.
     *
     * @param orgList
     * @return
     */
    public static boolean pushMessageToOrg(List<String> orgList){
        if (orgList.isEmpty()){
            log.error("机构列表为空，推送失败！");
            return false;
        }
        //遍历机构列表
        orgList.forEach(org->{
            //当前在线用户存在该机构下的人员
            if (connectSession.containsKey(org)){
                List<Session> sessionList = connectSession.get(org);
                if (sessionList.isEmpty()){
                    log.error("当前该机构在线用户为空");
                    return;
                }
                //给该机构每个在线用户推送消息
                sessionList.forEach(session -> {
                    try {
                        session.getBasicRemote().sendText("您有一条新的待办消息！");
                    } catch (IOException e) {
                        log.error("推送消息异常！");
                        e.printStackTrace();
                    }
                });
            }
        });

        return false;
    }

    /**
     * 连接关闭调用.
     */
    @OnClose
    public void close(Session session) {
        log.info("用户下线>>>连接关闭！");
        Map<String, String> pathParameters = session.getPathParameters();
        String orgId = pathParameters.get("orgId");
        connectSession.get(orgId).remove(session);
        //当前机构没有用户在线
        if(connectSession.get(orgId).isEmpty()){
            connectSession.remove(orgId);
        }
        log.info("移除用户session，当前所有在线用户为【{}】", connectSession);
    }

    /**
     * 通信发生异常时调用.
     */
    @OnError
    public void connectError(Session session, Throwable error) {
        log.error("连接发生异常：异常连接【{}】 异常信息【{}】", session, error.getMessage());
        log.error("异常堆栈：{}", error);
    }

}
